package com.base.common.util.collection;

import java.util.concurrent.LinkedBlockingQueue;

/**
 * 当队列中的数据少于给定的容量*factor时，则调用preproduce()将队列填充满
 * 
 * @author jiaqiang.yan
 * @date 2011-7-20
 * @email jiaqiang.yan@qunar.com
 * @version $id$
 */
public abstract class PreproduceBlockingQueue<E> extends LinkedBlockingQueue<E> {
    private static final long serialVersionUID = -7590174513950713914L;

    private static final float DEFAULT_FACTOR = 0.25f;
    private final int leastRemainingCapacity;

    public PreproduceBlockingQueue(int capacity) {
        this(capacity, DEFAULT_FACTOR);
    }

    public PreproduceBlockingQueue(int capacity, float preproduceFactor) {
        super(capacity);
        if (preproduceFactor >= 1) {
            throw new IllegalArgumentException("preproduce factor must be less than 1.0 !");
        }
        leastRemainingCapacity = (int) (capacity * preproduceFactor);
    }

    @Override
    public E take() throws InterruptedException {
        E E = super.take();
        tryPreproduce();
        return E;
    }

    /**
     * 这里的同步没必要使用父类的Lock，这里仅仅需要两个
     * 
     * @return
     */
    private boolean isNeedPreproduce() {
        return remainingCapacity() <= leastRemainingCapacity;
    }

    private synchronized void tryPreproduce() throws InterruptedException {
        if (isNeedPreproduce()) {
            for (int i = 0; i < remainingCapacity(); i++) {
                put(preproduce());
            }
        }
    }

    /**
     * 生成元素，将队列空余的空间填满
     */
    public abstract E preproduce();
}
